﻿using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using JetBrains.ReSharper.Psi;
using JetBrains.Util;

namespace MugenMvvmToolkit.ReSharper.PluginModels
{
    public struct WrapperMetaModel
    {
        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref="WrapperMetaModel" /> class.
        /// </summary>
        public WrapperMetaModel([NotNull] ITypeElement element, [NotNull] IAttributeInstance attribute,
            [NotNull] TypeProvider typeProvider)
            : this()
        {
            if (element == null)
                throw new ArgumentNullException("element");
            if (attribute == null)
                throw new ArgumentNullException("attribute");
            if (typeProvider == null) throw new ArgumentNullException("typeProvider");

            int priority = 0;
            object value = attribute.NamedParameter("Priority").ConstantValue.Value;
            if (value != null)
                int.TryParse(value.ToString(), out priority);

            var name = attribute.NamedParameter("Name").ConstantValue.Value as string;
            if (string.IsNullOrWhiteSpace(name))
                name = element.GetMemberName();

            AttributeValue[] types = attribute.NamedParameter("Types").ArrayValue;
            if (types == null)
                SupportedTypes = EmptyList<IType>.InstanceList;
            else
                SupportedTypes = types
                    .Select(attributeValue => attributeValue.TypeValue)
                    .ToList();

            Type = TypeFactory.CreateType(element);
            Name = name;
            Priority = priority;
            IsDisposable = Type.IsOfType(typeProvider.DisposableInterface);
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref="WrapperMetaModel" /> class.
        /// </summary>
        public WrapperMetaModel([NotNull] IDeclaredType type, [NotNull] string name, int priority,
            [NotNull] IList<IType> supportedTypes, bool isDisposable)
            : this()
        {
            if (type == null) throw new ArgumentNullException("type");
            if (name == null) throw new ArgumentNullException("name");
            if (supportedTypes == null) throw new ArgumentNullException("supportedTypes");
            Type = type;
            Name = name;
            Priority = priority;
            SupportedTypes = supportedTypes;
            IsDisposable = isDisposable;
        }

        #endregion

        #region Properties

        public IDeclaredType Type { get; private set; }

        public string Name { get; private set; }

        public int Priority { get; private set; }

        public IList<IType> SupportedTypes { get; set; }

        public bool IsDisposable { get; private set; }

        #endregion

        #region Methods

        public bool IsSupported(IType type)
        {
            return SupportedTypes.All(supportedType => !supportedType.IsResolved || type.IsOfType(supportedType));
        }

        #endregion
    }
}